iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 1
2
自我挑戰組

Android 菜鳥村-開發基礎 30篇系列 第 2

[ Day 1 下 ] Kotlin 變數 val var / 基本型態 及 轉換 …

  • 分享至 

  • xImage
  •  

本篇文章大概會討論到下列幾個主軸

  • 基本型態

  • 當宣告變數時,發生了什麼事?

  • 變數數值是如何指派給另一個變數的

  • 基礎型別之間的轉換

  • val 與 var 的差別

  • val 不能指向其他物件,但其指向物件本身可以作更改?

  • 當變數指派他的值給其他 var 變數,其他變數做物件本身變更,原變數也會跟著變更?

  • 產生新的物件

  • 基礎型態 / String / 一般的物件在傳遞上的差別

基本型態

kotlin 基本型態 包括:Byte、Short、Int、Long、Float、Double、Char與Boolean

但請注意 String 並不是

當宣告變數時,發生了什麼事?

當我們宣告一個變數時,我們可以指定他的型態

var a : Cat  = Cat ()

但Kotlin 也有自動判別的功能,例如下面編譯器就會自動指定一個型態給變數

var a = Cat ()

型態對編譯器很重要,打個比方,他不允許把一個 Dog 指派給 一個型態為 Cat 的變數,因為 Dog 不能用來執行 Cat 的行為。
為了防止導致bug 編譯器需要知到變數的型態。

變數數值是如何指派給另一個變數的

我們可以變數指派給另一個變數,但必須確定兩者型態是相同的。
運作說明如下:

var a = Cat ()
var b = a // attention 只有 var 才可以轉換值下面會說明

如上一部份所示,變數A可以訪問(access) Cat 類別的物件

var a = Cat ()

var b = a 

將a的值指派給b時,b取得指向同一物件的reference(參考)
b 和 a 都可以訪問(access)同一物件。也就是說b和a保存同一物件的reference(參考)。

所以實際上並不是在指派給b時,建立另一個Int物件讓b指向,而是讓 b 和 a 指向同一物件

b.equals(a) 會是 true


fun main() {
   
var a :Cat = Cat ()
    
var b = a

 println(b.equals(a))   
 
}

//true

基礎型別之間的轉換

上面有提到型態對編譯器很重要,兩個不同型態的變數,是不能互相傳遞值的
下面這樣會報錯,兩者型態不同,基本上無法編譯


var a :Int = 5

var c:Long = a

但在基礎型態中 , 但我們可以試著將他轉換成另一種型別


var a :Int = 5

var c:Long = a.toLong()

編譯器呼叫 Int 5 的 toLong()函式,會產生的新的值 Long 5,並將這個數值 傳給 c 變數,建立型態為Long 的 c 變數。

val 與 var 的差別

val 和 var 的差別在於 var 可以set Value 也可以 get value (可讀可寫),而 val 不行, val 只能get value(可讀) , 對一個變數的引用 是呼叫這個變數的getter方法, val 變數 在初始化時傳遞值給他,因為沒有set value, 所以並無法從新設定這個變數的值 ,這也就是當你初始化一個val 變數之後,再把其他值指派給他會報錯的原因。

1- 會報錯,無法編譯


    val a = 5

        a = 6  
 

2- 可以從新設定 a 變數的值 , 不會報錯


    var a = 5

        a = 6  
 

val 不能指向其他物件,但其指向物件本身可以作更改?

這個情形通常見於 一般的物件, 但基本型態是無法的哦
舉例如下:

val 變數 a 不能再指向其他 物件


    val a = Cat()

     a = Cat()  // 會報錯,無法編譯
 

但我們可以改變本身 Cat() 的數值


     fun main() {
   
     val a = Cat()
     
     // 更改 Cat() 類別的變數 name

      a.name = "hello Kitty"  
      
      a.name =  "Garfield"
      
      println(a.name)
      
      // result : Garfield
    
     }

這時候保存的還是同一個物件 , 並沒有產生或引用新的物件哦。

當變數指派他的值給其他 var 變數,其他變數做物件本身變更,原變數也會跟著變更?

還記得上面我們所說的,將a的值指派給b時,b可取得指向同一物件的reference(參考),b 和 a 都可以訪問(access) 同一物件。

    val b = a 

延續 上一個 Topic , 今天將 型別 為 Cat 的變數, 換成陣列 , val a 將其指向的物件(array 物件)指派給另一個變數 val b ,這時候 a 和 b 會指向同一物件。

       val a = arrayOf(1,2,3)
       val b = a 

在指派值給b之後,變數b改變 position 0 的數字

       b[0] = 8

結果連 a 變數都改變了 , 為啥?

    
    fun main() {
   
    val a = arrayOf(1,2,3)

    var b = a

   b[0] = 8  
    
    
   for (i in 0 until a.size){
     
   println(a[i])
     
     } 
     
       //result 
      //8
      //2
      //3
  }
 

原來是因為 這兩個變數保存 同一物件的 reference (指向同一物件) , 當一個變數對這物件作非本質上的更改時會影響到其他變數

產生新的物件

物件有可能發生本質上的改變 ,像 MutableList 產生的物件 在調用 sortedByDescending ()做降序排列時,就會產生新的物件 , 所以下面 b 和 a 會指向同一物件 , a 會把同一個物件的 reference 給 b , 而 c 則是 a 所指向的 物件執行 sortedByDescending ()所產生新的物件 , 所持有的 物件 reference 和 a 或 b 都不同

    
    fun main() {
   
    val a =mutableListOf<Int>(1,2,3)

    var b = a
    
    var c = a.sortedByDescending{it}
    
    println(b === a)

    // result : true
    
    println(c === a)
    
    // result : false
 
  }
 

基礎型態 / String / 一般的物件在傳遞上的差別

基礎型態

基礎型態,是 Immutable (無法像物件那樣做更改, 他只是個值) ,上面我們有提到 Kotlin 在基礎型態有 Byte、Short、Int、Long、Float、Double、Char與Boolean,
在這些型態被傳遞 , 傳遞是傳遞實際基本型態的 值 , 像是 5 (Int) , True (Bolean), 103.0 (Double),會把這些數值傳給 另一個變數

一般的物件

物件是 mutable (可以做非本質上的更改 , 像上面提到的那樣),物件和變數關係,是將物件 reference(參考) 傳遞給另一個變數,並非傳遞實際的數值,讓這值個變數可以access (訪問)這個物件,reference 可以看作是 找這物件的地址 。

String

String 是物件 , 但是 和 基礎型態 一樣 Immutable , JVM 有一個 String Pool , String Pool 負責將不同 字的片段 組成 一個物件 , 當編譯器看到文字時,它將在池中查找。如果找到匹配項,則變數會指向 舊有的String 物件,系統並且不會創建新的 String 物件 給變數引用。

這是使String 物件不可變原因在於: 在 String Pool 中,一個 String 物件可能具有一個或多個變數指向它。如果多個變數甚至不知道指向同一 String 物件,那麼如果其中一個引用修改了該 String 物件,那會照成混亂。這就是為什麼String 物件是 Immutable 。

下面 b 變數 和 a 變數 指向同一個 String 物件 ,

c 變數 會指向新的物件 , 這個物件是從 String Pool 找到匹配 的另一個 String 物件 , 並非是 "1" String 物件 做實值上更改

    fun main() {
   
    val a = "1"
    
    var b = a  

    var c = a +"2"
    
   println(b === a)

    // result : true
    
    println(c === a)
    
    // result : false
 
  }

結尾

好的 , 今天結束 , 做個練習吧 ,測試下列四個組數值是否指到同一物件及值的變化,是否和想像的一樣 答案明天會公佈

第一組


fun main (){

 var a = 0
 
 var b = a
 
 b = 1 
 

}

第二組

fun main (){

 var sa = "abcd"
 
 var sb =  sa 
  
 sb.replace("a","c") 
 
}

第三組


fun main (){

 var la = mutableListOf(1,2,3,4)
 
 var lb =  la
 
 lb.clear()
 

}

第四組

data class Test (var id:Int, var name :String)

fun main (){

 var ta = Test(0,"aaa")
 
 var tb =  ta
 
 tb.id = 1
 
}

上一篇
[Day1 上] 開賽前言
下一篇
[Day 2 上]
系列文
Android 菜鳥村-開發基礎 30篇32
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言